"""
Case Type   : 资源池化集群系统内部使用工具
Case Name   : failover之后执行备份恢复操作
Create At   : 2024/04/19
Owner       : @kyleze
Description :
    1.踢出主机，等待failover完成
    2.查询新主机
    3.主机上初始化目录
    4.主机上添加备份实例
    5.主机上执行全量备份
    6.停止集群
    7.主机执行恢复
    8.备机执行恢复
    9.启动集群
Expect      :
    1.集群恢复正常
    2.成功
    3.成功
    4.成功
    5.备份成功
    6.成功
    7.主机恢复成功
    8.备机恢复成功
    9.成功
History     :
"""

import os
import unittest
import time

from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH

from yat.test import Node
from yat.test import macro


@unittest.skipIf(
    "dms_res" not in Common().get_sh_result(
    Node("PrimaryDbUser"), f"source {macro.DB_ENV_PATH}; "
    f"cm_ctl query -Cvidp"), "非资源池化环境不执行")
class SharedStorageGsProbackup(unittest.TestCase):
    def setUp(self):
        self.log = Logger()
        self.log.info(f"-----{os.path.basename(__file__)[:-3]} start-----")
        self.constant = Constant()
        self.primary_sh = CommonSH('PrimaryDbUser')
        self.st1_sh = CommonSH('Standby1DbUser')
        self.st2_sh = CommonSH('Standby2DbUser')
        self.pri_com = Common('PrimaryDbUser')
        self.st1_com = Common('Standby1DbUser')
        self.st2_com = Common('Standby2DbUser')
        self.pri_node = Node(node='PrimaryDbUser')
        self.st1_node = Node(node='Standby1DbUser')
        self.st2_node = Node(node='Standby2DbUser')
        self.database = self.pri_node.db_name
        self.port = self.pri_node.db_port
        self.parent_path = os.path.dirname(macro.DB_INSTANCE_PATH)
        self.backup_path = os.path.join(self.parent_path,
                                        "backupset/backup_dir_001")
        self.instance_name = 'probackup_001'
        self.primary_script = "sharestorage_probackup_primary_restore.sh"
        self.standby_script = "sharestorage_probackup_standby_restore.sh"
        self.target_path = os.path.join(macro.DB_BACKUP_PATH, 'probackup_006')
        self.log.info("-----检查数据库状态是否正常-----")
        status = self.primary_sh.get_db_cluster_status()
        self.assertTrue("Degraded" in status or "Normal" in status)
        cmd = f'source {macro.DB_ENV_PATH};' \
              f'cat $DSS_HOME/cfg/dss_vg_conf.ini |cut -d ":" -f 1'
        vgname_infor = self.pri_node.sh(cmd).result().strip()
        self.vgname = "+" + vgname_infor.split('\n')[0].strip() + \
                      ",+" + vgname_infor.split('\n')[1].strip()

    def test_gs_pro_backup(self):
        step = '--step1:踢出主机，等待failover完成 expect:集群恢复正常'
        self.log.info(step)
        result = self.primary_sh.exec_cm_ctl('stop', '-n 1')
        self.log.info(result)
        self.assertIn(self.constant.cm_stop_node_success_msg,
                      result, "执行失败:" + step)
        time.sleep(10)
        result = self.primary_sh.exec_cm_ctl('start', '-n 1')
        self.log.info(result)
        self.assertIn(self.constant.cm_start_node_success_msg,
                      result, "执行失败:" + step)
        for i in range(60):
            self.log.info("----第" + str(i + 1) + "次查询集群状态----")
            time.sleep(2)
            cluster_detail = self.primary_sh.get_db_cluster_status("detail")
            self.log.info(cluster_detail)
            if "Degraded" in cluster_detail or "Primary Normal" in \
                    cluster_detail:
                break
            elif i == 59:
                cluster_res = "Degraded" or "Primary Normal" in cluster_detail
                self.assertTrue(cluster_res, "执行失败" + step)
        result = self.primary_sh.execut_db_sql(
            'select * from pg_stat_get_stream_replications()')
        self.assertNotIn('Primary', result, "执行失败:" + step)

        step = '--step2:查询新主 expect:成功--'
        self.log.info(step)
        result = self.primary_sh.exec_cm_ctl('query', '-Civdpw')
        self.log.info(result)
        if 'Primary' in result.split('\n')[-2]:
            self.log.info(result.split('\n')[-2])
            self.new_pri_sh = self.st1_sh
            self.new_pri_node = self.st1_node
            self.new_pri_com = self.st1_com
        elif 'Primary' in result.split('\n')[-1]:
            self.log.info(result.split('\n')[-1])
            self.new_pri_sh = self.st2_sh
            self.new_pri_node = self.st2_node
            self.new_pri_com = self.st2_com

        step = '--step3:主机上初始化目录 expect:成功--'
        self.log.info(step)
        result = self.new_pri_sh.exec_pro_backup_init(self.backup_path)
        self.log.info(result)
        self.assertTrue(result, "执行失败:" + step)

        step = '--step4:主机上添加备份实例，instance-id设为0 expect:成功--'
        self.log.info(step)
        result = self.new_pri_sh.exec_pro_back_add(
            self.backup_path, self.instance_name,
            f"--enable-dss --vgname='{self.vgname}'")
        self.log.info(result)
        self.assertTrue(result, "执行失败:" + step)

        step = '--step5:主机上执行全量备份 expect:成功--'
        self.log.info(step)
        result = self.new_pri_sh.exec_pro_backup_backup(
            self.backup_path, self.instance_name, 'full',
            f"{self.pri_node.db_name}",
            f"--vgname='{self.vgname}' -j 128", True)
        self.log.info(result)
        self.assertIn('completed', result, "执行失败:" + step)
        self.backup_id = ''
        for backupid_msg in result.splitlines():
            if 'completed' in backupid_msg:
                self.backup_id = backupid_msg.split()[2]
        self.log.info('备份ID为：' + self.backup_id)

        step = '--step6:停止集群 expect:成功--'
        self.log.info(step)
        result = self.new_pri_sh.exec_cm_ctl('stop')
        self.log.info(result)
        self.assertIn(self.constant.cm_stop_success_msg, result,
                      "停止集群失败")

        step = '--step7:主机执行恢复 expect 成功--'
        self.log.info(step)
        self.st2_com.scp_file(
            self.new_pri_node, self.primary_script, self.target_path)
        cmd = f'source {macro.DB_ENV_PATH};cd {self.target_path}; ' \
              f'sh sharestorage_probackup_primary_restore.sh'
        result = self.new_pri_node.sh(cmd).result()
        self.log.info(result)
        self.assertIn('successfully start dssserver', result, "dss启动失败")
        result = self.new_pri_sh.exec_pro_backup_restore(
            self.backup_path, self.instance_name, self.backup_id,
            restore_cmd=f'-D {macro.DB_INSTANCE_PATH} -j 128', get_detail=True)
        self.log.info(result)
        self.assertTrue(result, "主机执行恢复失败")
        self.log.info('----停止dss server----')
        stop_dss_cmd = f"source {macro.DB_ENV_PATH};dsscmd stopdss;"
        res = self.new_pri_com.get_sh_result(self.new_pri_node, stop_dss_cmd)
        self.log.info(res)
        self.assertIn('Succeed to stop server.', res, "dss停止失败")

        step = '--step7:启动集群 expect:成功--'
        self.log.info(step)
        result = self.primary_sh.exec_cm_ctl('start')
        self.log.info(result)
        self.assertIn(self.constant.cm_start_success_msg, result,
                      "执行失败" + step)

    def tearDown(self):
        self.log.info('----清理环境----')
        result = self.primary_sh.exec_cm_ctl('switchover', '-a')
        self.log.info(result)
        clear_cmd = f"rm -rf {self.backup_path} {self.target_path}"
        self.log.info(clear_cmd)
        clear_msg = self.new_pri_node.sh(clear_cmd).result()
        self.log.info(clear_msg)
        self.assertIn(self.constant.cm_switchover_success_msg,
                      result, "恢复集群失败")
        self.assertIn('', clear_msg, '删除目录失败')
        self.log.info(f"-----{os.path.basename(__file__)} end-----")

